﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;

namespace Firefly.Framework.Collections.Generic
{
    public class UpdateableList<T> : IUpdateableList<T>
    {
        protected List<T> _innerList = null;

        public UpdateableList()
        {
            _innerList = new List<T>();
        }

        protected void NotifyCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (!IsUpdating)
            {
                if (CollectionChanged != null)
                {
                    CollectionChanged(this, e);
                }
            }
        }

        protected void NotifyPropertyChanged(string property)
        {
            if (!IsUpdating)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(property));
                }
            }
        }

        protected void NotifyUpdateComplete()
        {
            NotifyCollectionChangedEventArgs eventArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);

            if (CollectionChanged != null)
            {
                CollectionChanged(this, eventArgs);
            }
        }

        public virtual void Sort()
        {
            _innerList.Sort();
        }

        public virtual void Sort(Comparison<T> comparision)
        {
            _innerList.Sort(comparision);
        }

        public virtual void Sort(IComparer<T> comparer)
        {
            _innerList.Sort(comparer);
        }

        public void Sort(int index, int count, IComparer<T> comparer)
        {
            _innerList.Sort(index, count, comparer);
        }

        #region IList<T> Members

        public virtual int IndexOf(T item)
        {
            return _innerList.IndexOf(item);
        }

        public virtual void Insert(int index, T item)
        {
            _innerList.Insert(index, item);
            NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
            NotifyPropertyChanged("Count");
        }

        public virtual void RemoveAt(int index)
        {
            T item = _innerList[index];
            _innerList.RemoveAt(index);
            NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item));
            NotifyPropertyChanged("Count");
        }

        public virtual T this[int index]
        {
            get
            {
                return _innerList[index];
            }

            set
            {
                if (index < Count)
                {
                    if (!(value is DBNull) && value != null)
                    {
                        T oldItem = _innerList[index];
                        _innerList[index] = value;
                        NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, oldItem, value));
                    }
                    else
                    {
                        throw new ArgumentNullException("value");
                    }
                }
                else
                {
                    throw new ArgumentOutOfRangeException("index");
                }
            }
        }

        #endregion

        #region ICollection<T> Members

        public virtual void Clear()
        {
            List<T> copyItems = new List<T>();

            for (int i = 0; i < _innerList.Count; i++)
            {
                copyItems.Add(_innerList[i]);
            }

            _innerList.Clear();
            NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, copyItems));
            NotifyPropertyChanged("Count");
        }

        public virtual bool Contains(T item)
        {
            return _innerList.Contains(item);
        }

        public virtual void CopyTo(T[] array, int index)
        {
            _innerList.CopyTo(array, index);
        }

        public virtual int Count
        {
            get { return _innerList.Count; }
        }

        public virtual bool IsReadOnly
        {
            get { return false; }
        }

        public virtual bool Remove(T item)
        {
            if (_innerList.Contains(item))
            {
                int index = _innerList.IndexOf(item);
                _innerList.Remove(item);

                if (index > -1)
                {
                    NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index));
                }
                else
                {
                    NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove));
                }

                NotifyPropertyChanged("Count");
                return true;
            }
            else
            {
                return false;
            }
        }

        public virtual void Add(T item)
        {
            if (!(item is DBNull) && item != null)
            {
                _innerList.Add(item);
                NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
                NotifyPropertyChanged("Count");
            }
        }

        void ICollection<T>.Add(T item)
        {
            if (!(item is DBNull) && item != null)
            {
                _innerList.Add(item);
                NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
                NotifyPropertyChanged("Count");
            }
        }

        void ICollection<T>.Clear()
        {
            List<T> copyItems = new List<T>();

            for (int i = 0; i < _innerList.Count; i++)
            {
                copyItems.Add(_innerList[i]);
            }

            _innerList.Clear();
            NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, copyItems));
            NotifyPropertyChanged("Count");
        }

        bool ICollection<T>.Contains(T item)
        {
            return _innerList.Contains(item);
        }

        void ICollection<T>.CopyTo(T[] array, int arrayIndex)
        {
            _innerList.CopyTo(array, arrayIndex);
        }

        int ICollection<T>.Count
        {
            get { return _innerList.Count; }
        }

        bool ICollection<T>.IsReadOnly
        {
            get { return false; }
        }

        bool ICollection<T>.Remove(T item)
        {
            if (_innerList.Contains(item))
            {
                _innerList.Remove(item);
                NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item));
                NotifyPropertyChanged("Count");
                return true;
            }
            else
            {
                return false;
            }
        }

        #endregion

        #region IEnumerable<T> Members

        public IEnumerator<T> GetEnumerator()
        {
            return _innerList.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return _innerList.GetEnumerator();
        }

        #endregion

        #region INotifyCollectionChanged Members

        public event NotifyCollectionChangedEventHandler CollectionChanged;

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region IUpdateableCollection Members

        public bool IsUpdating { get; protected set; }

        public void BeginUpdate()
        {
            IsUpdating = true;
        }

        public void EndUpdate()
        {
            IsUpdating = false;
            NotifyUpdateComplete();
        }

        #endregion

        #region IList Members

        public int Add(object value)
        {
            Add((T)value);
            return 1;
        }

        public bool Contains(object value)
        {
            return Contains((T)value);
        }

        public int IndexOf(object value)
        {
            return IndexOf((T)value);
        }

        public void Insert(int index, object value)
        {
            Insert(index, (T)value);
        }

        public bool IsFixedSize
        {
            get { return (_innerList as IList).IsFixedSize; }
        }

        public void Remove(object value)
        {
            Remove((T)value);
        }

        object IList.this[int index]
        {
            get
            {
                return this[index];
            }
            set
            {
                this[index] = (T)value;
            }
        }

        #endregion

        #region ICollection Members

        public void CopyTo(Array array, int index)
        {
            (_innerList as IList).CopyTo(array, index);
        }

        public bool IsSynchronized
        {
            get { return (_innerList as IList).IsSynchronized; }
        }

        public object SyncRoot
        {
            get { return (_innerList as IList).SyncRoot; }
        }

        #endregion
    }
}
